<!doctype html>
<meta charset="utf-8">
<meta name="viewport" content="width = device-width, initial-scale = 1.0, user-scalable = no">
<title>Car</title>

<script src="requestAnimationFramePolyfill.js"></script>
<canvas width="550" height="400" style="border: 1px dashed black"></canvas>

<script type="text/javascript">

//--- The sprite object
//*** Note: this spriteObject uses an additional Boolean property called 
//accelerate which is used to determine when the car should accelerate
var spriteObject =
{
  sourceX: 0,
  sourceY: 0,
  sourceWidth: 64,
  sourceHeight: 64,
  width: 64,
  height: 64,
  x: 0,
  y: 0,
  vx: 0,
  vy: 0,
  visible: true,
  rotation: 0,
  
  //Physics properties
  accelerationX: 0, 
  accelerationY: 0,
  accelerate: false,
  speed: 0, 
  speedLimit: 5, 
  friction: 0.92,
  bounce: -0.7,
  gravity: 0.3,
    
  //Getters
  centerX: function()
  {
    return this.x + (this.width / 2);
  },
  centerY: function()
  {
    return this.y + (this.height / 2);
  },
  halfWidth: function()
  {
    return this.width / 2;
  },
  halfHeight: function()
  {
    return this.height / 2;
  }
};

//--- The main program

//The canvas
var canvas = document.querySelector("canvas"); 
var drawingSurface = canvas.getContext("2d");

//Object arrays
var sprites = [];
var assetsToLoad = [];
var assetsLoaded = 0;

//The touch point
var touchX = 0;
var touchY = 0;

//The car
var car = Object.create(spriteObject);
car.sourceX = 64;
car.x = canvas.width / 2 - car.halfWidth();
car.y = canvas.height / 2 - car.halfHeight();
sprites.push(car);

//Load the tilesheet image
var image = new Image();
image.addEventListener("load", loadHandler, false);
image.src = "../images/vehicles.png";
assetsToLoad.push(image);

//Add listeners
canvas.addEventListener("touchmove", touchmoveHandler, false);
canvas.addEventListener("touchstart", touchstartHandler, false);
canvas.addEventListener("touchend", touchendHandler, false);

//The angle between the touch point and the center of the car
var angle = 0;

//Game states
var LOADING = 0;
var PLAYING = 1;
var gameState = LOADING;

update();

function touchmoveHandler(event)
{ 
  //Find the touch point's x and y position.
  //Subtract the canvas's top and left offset
  touchX = event.targetTouches[0].pageX - canvas.offsetLeft;
  touchY = event.targetTouches[0].pageY - canvas.offsetTop;
  event.preventDefault(); 
}

function touchstartHandler(event)
{
	car.accelerate = true;
	event.preventDefault(); 
}

function touchendHandler(event)
{	
  car.accelerate = false;   
  event.preventDefault(); 
}

function playGame()
{ 
  if(car.accelerate)
	{
		//Increase the car's speed if it's under the speed limit
	  if(car.speed < car.speedLimit)
	  {
		  car.speed += 0.1;
		}
		//Add some optional drag
		//car.speed *= car.friction;  
	}
	else
	{
		//Add friction to the speed if the car is 
		//not accelerating
		car.speed *= car.friction; 
	}
	
	/*
	The code needs to prevent the car from rapidly changing direction if the
	touch point is very close to it or directly over it. The code figures out
	the distance between the car and the touch point. It then prevents the angle from
	updating if that angle is less than half the car's width. Tweak this for
	your own games as you need to.
	*/
	
	//Figure out the distance between the touch point and the center of the car
  var vx = touchX - (car.x + car.width / 2); 
  var vy = touchY - (car.y + car.height / 2);  
  distance = Math.sqrt(vx * vx + vy * vy);
  
	//Calculate the acceleration based on the angle of rotation if the 
	//touch is outside the car's radius
	if(distance > car.halfWidth())
	{
	  //Accelerate the car based on the angle
		angle = Math.atan2(touchY - car.centerY(), touchX - car.centerX());
	  car.accelerationX = car.speed * Math.cos(angle); 
		car.accelerationY = car.speed * Math.sin(angle);
	}
	else
	{
	  //Slow the car to a stop if it's near the touch
	  car.accelerationX *= 0.8; 
		car.accelerationY *= 0.8;
	}
	
	//Update the car's velocity
	car.vx = car.accelerationX; 
	car.vy = car.accelerationY;
	
	//Move and rotate the car
	car.x += car.vx;
	car.y += car.vy;
	car.rotation = angle * (180 / Math.PI);
}

function update()
{ 
  //The animation loop
  requestAnimationFrame(update, canvas);
  
  //Change what the game is doing based on the game state
  switch(gameState)
  {
    case LOADING:
      console.log("loading...");
      break;
    
    case PLAYING:
      playGame();
      break;
  }
  
  //Render the game
  render();
}

function loadHandler()
{ 
  assetsLoaded++;
  if(assetsLoaded === assetsToLoad.length)
  {
    gameState = PLAYING;
  }
}

function render()
{ 
  drawingSurface.clearRect(0, 0, canvas.width, canvas.height);
  
  //Display the sprites
  if(sprites.length !== 0)
  {
	  for(var i = 0; i < sprites.length; i++)
	  {
	    var sprite = sprites[i];
	     
	    //Save the current state of the drawing surface
	    //before it's rotated
	    drawingSurface.save();
	  
	    //Rotate the canvas
    	drawingSurface.translate
    	(
    	  Math.floor(sprite.x + sprite.halfWidth()), 
    	  Math.floor(sprite.y + sprite.halfHeight())
    	);
	    drawingSurface.rotate(sprite.rotation * Math.PI / 180);
    
	    if(sprite.visible)
	    {
		    drawingSurface.drawImage
		    (
		      image, 
		      sprite.sourceX, sprite.sourceY, 
		      sprite.sourceWidth, sprite.sourceHeight,
		      Math.floor(-sprite.halfWidth()), Math.floor(-sprite.halfHeight()), 
		      sprite.width, sprite.height
		    );
	    }
	     
      //Restore the drawing surface to its 
      //state before it was rotated
      drawingSurface.restore();
	  }
  }
}

</script>